package com.apes.framework.plugin.soe.metadata;

import com.alibaba.fastjson.annotation.JSONField;
import com.apes.framework.jpa.BaseModel;
import com.apes.framework.jpa.DefaultPersistListener;
import com.apes.framework.jpa.comment.Comment;
import com.apes.framework.jpa.generator.ApesGenerator;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.annotations.SelectBeforeUpdate;
import org.springframework.util.StringUtils;

import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;

/**
 * 功能：场景编排（场景流）
 *
 * @author xul
 * @create 2018-09-21 11:56
 */
@Getter
@Setter
@SelectBeforeUpdate
@DynamicInsert
@DynamicUpdate
@Entity
@EntityListeners(DefaultPersistListener.class)
@Table(name = SceneFlow.CONST_TABLE_NAME, indexes = {
        @Index(name = "idx_scene_flow_source", columnList = "scene_id, source_business_type_id"),
        @Index(name = "idx_scene_flow_target", columnList = "scene_id, target_business_type_id")})
public class SceneFlow extends BaseModel {
    public static final String CONST_TABLE_NAME = "soe_scene_flow";

    @Id
    @Column(name = "id", length = 32)
    @ApesGenerator(code = CONST_TABLE_NAME, name = "场景流")
    @Comment("编码")
    private String id;

    @Column(name = "name", nullable = false, length = 60)
    @Comment("名称")
    private String name;

    @Column(name = "step", nullable = false, length = 10)
    @Comment("步骤")
    private String step;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "source_business_type_id", referencedColumnName = "id", nullable = false)
    @Comment("凭证类型（源）")
    private BusinessType sourceBusinessType;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "outbound", referencedColumnName = "id") //, nullable = false
    @Comment("出站")
    private BusinessAction outbound;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "target_business_type_id", referencedColumnName = "id") //, nullable = false
    @Comment("凭证类型（目标）")
    private BusinessType targetBusinessType;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "inbound", referencedColumnName = "id") //, nullable = false
    @Comment("入站")
    private BusinessAction inbound;

    @Column(name = "sync", nullable = false, columnDefinition = "number(1,0) default 1")
    @Comment("是否同步调用")
    private boolean sync = true;

    @Column(name = "started", nullable = false, columnDefinition = "number(1,0) default 0")
    @Comment("是否启动")
    private boolean started = false;

    public void setStarted(boolean started) {
        if (started && this.finish) {
            throw new RuntimeException("一个场景流不允许同时为开始和结束节点！");
        }
        this.started = started;
    }

    @Column(name = "finish", nullable = false, columnDefinition = "number(1,0) default 0")
    @Comment("是否结束")
    private boolean finish = false;

    public void setFinish(boolean finish) {
        if (this.started && finish) {
            throw new RuntimeException("一个场景流不允许同时为开始和结束节点！");
        }
        this.finish = finish;
    }


    @Column(name = "once", nullable = false, columnDefinition = "number(1,0) default 1")
    @Comment("执行一次")
    private boolean once = true;


    @Column(name = "valid", nullable = false, columnDefinition = "number(1,0) default 1")
    @Comment("是否有效")
    private boolean valid = true;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "scene_id", referencedColumnName = "id", nullable = false)
    @Comment("场景")
    private Scene scene;

    @Column(name = "condition", length = 120)
    @Comment("文本条件")
    private String condition;

    @OneToMany(mappedBy = "sceneFlow", cascade = CascadeType.ALL, orphanRemoval = true)
    @Comment("条件因子")
    private Set<SceneFlowFactor> sceneFlowFactors = new HashSet();

    public Set<SceneFlowFactor> getSceneFlowFactors() {
        if (sceneFlowFactors == null) return null;
        for (SceneFlowFactor flowFactor : sceneFlowFactors) {
            flowFactor.setSceneFlow(this);
        }
        return sceneFlowFactors;
    }

    @Transient
    @JSONField(serialize = false)
    private boolean auto; //是否自动执行节点

    public boolean isAuto() {
        return getOutbound() != null || getInbound() != null;
    }

    public String buildScript() {
        if ((sceneFlowFactors == null || sceneFlowFactors.isEmpty()) && StringUtils.isEmpty(condition)) throw new RuntimeException("场景流条件或文本条件不能为空！" + this.getName());
        StringBuffer sb = new StringBuffer();
        for (SceneFlowFactor flowFactor : sceneFlowFactors) {
            if (sb.length() > 0) {
                sb.append(" && ");
            }
            sb.append(flowFactor.buildScript());
        }
        if (!StringUtils.isEmpty(condition)) {
            if (sb.length() > 0) {
                sb.append(" && ");
            }
            sb.append(condition);
        }
        return sb.toString();
    }

}
